package com.alibaba.yinan.domain.execution.executor;

import com.alibaba.cola.exception.BizException;
import com.alibaba.yinan.domain.resource.ResourceAllocator;
import com.alibaba.yinan.domain.task.Task;
import com.alibaba.yinan.domain.task.enums.TaskEvent;
import com.alibaba.yinan.domain.task.enums.TaskType;
import com.alibaba.yinan.domain.task.service.lifecycle.TaskStateMachineHandler;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author yinan
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class TaskExecuteManager {

    private final List<TaskExecutor> executors;
    private final TaskStateMachineHandler stateHandler;
    private final ResourceAllocator resourceAllocator;

    private Executor executor;

    /** 幂等执行记录 */
    private final ConcurrentMap<String, Boolean> executedTasks = new ConcurrentHashMap<>();

    @PostConstruct
    public void initExecutor() {
        ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
        threadPool.setCorePoolSize(4);
        threadPool.setMaxPoolSize(10);
        threadPool.setQueueCapacity(100);
        threadPool.setThreadNamePrefix("task-executor-");
        threadPool.initialize();
        this.executor = threadPool;
    }

    /**
     * 异步执行任务，支持：
     * - 状态流转
     * - 任务类型分发
     * - 资源占用/释放
     * - 重试
     * - 幂等
     */
    public void executeAsync(Task task, int maxRetry) {
        // 幂等检查
        if (executedTasks.putIfAbsent(task.getId(), true) != null) {
            log.warn("任务 {} 已经执行过，跳过", task.getId());
            return;
        }

        executor.execute(() -> {
            int attempt = 0;
            while (attempt <= maxRetry) {
                try {
                    log.info("任务 {} 开始执行，第 {} 次尝试", task.getId(), attempt + 1);

                    // 状态流转：RUNNING
                    task.changeState(TaskEvent.START, stateHandler);

                    // 调用对应类型执行器
                    TaskExecutor executor = findExecutor(task.getType());
                    executor.execute(task);

                    // 状态流转：COMPLETED
                    task.changeState(TaskEvent.COMPLETE, stateHandler);
                    log.info("任务 {} 执行成功", task.getId());
                    break;

                } catch (Exception e) {
                    attempt++;
                    log.error("任务 {} 执行失败，第 {} 次尝试，异常: {}", task.getId(), attempt, e.getMessage(), e);
                    task.changeState(TaskEvent.FAIL, stateHandler);

                    if (attempt > maxRetry) {
                        log.error("任务 {} 达到最大重试次数，执行失败", task.getId());
                        break;
                    }

                    try {
                        Thread.sleep(1000); // 可自定义重试间隔
                    } catch (InterruptedException ex) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                } finally {
                    // 释放占用的资源
                    resourceAllocator.releaseTaskSlots(task);
                }
            }
        });
    }

    private TaskExecutor findExecutor(TaskType type) {
        return executors.stream()
                .filter(e -> e.support(type))
                .findFirst()
                .orElseThrow(() -> new BizException("不支持的任务类型：" + type));
    }
}
